import { connect } from 'dva';
import * as THREE from 'three'
import { useEffect, useRef } from 'react';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js'

 const UvPage = (props) => {
   const sceneRef = useRef(null)
   const cameraRef = useRef(null)
   const rendererRef = useRef(null)
   const guiRef = useRef(null)
   const width = 1000; //宽度
   const height = 800; //高度
   useEffect(()=>{
    init()
   }, [])
   const init = () => {
      // 0.添加GUI
      const eventObj = {
        Fullscreen: function(){
         document.body.requestFullscreen()
        },
        Exitscreen: () => {
          document.exitFullscreen()
        }
      }
      guiRef.current = new GUI()
      guiRef.current.add(eventObj, "Fullscreen").name('全屏')
      guiRef.current.add(eventObj, "Exitscreen").name('退出全屏')

      // 1.创建3D场景对象Scene
      sceneRef.current = new THREE.Scene();

      // 4.创建物体
      setGeometry()

      // 2. 定义虚拟相机部分
      setCamera()

      // 5. 坐标辅助器
      const axesHelper = new THREE.AxesHelper(500)
      sceneRef.current.add(axesHelper)

      // 3.渲染器
      setRenderer()

      // 全屏 rendererRef.current.domElement.requestFullscreen()
      window.addEventListener("resize",()=>{
        rendererRef.current.setSize(window.innerWidth,window.innerHeight);
        cameraRef.current.aspect = window.innerWidth/window.innerHeight;
        cameraRef.current.updateProjectionMatrix()
      })

   }

   // 创建相机
   const setCamera = () => {
      // width和height用来设置Three.js输出的Canvas画布尺寸(像素px)
      cameraRef.current = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
      // 实例化一个透视投影相机对象
      // 根据需要设置相机位置具体值
      cameraRef.current.position.set(10, 10, 10);
      cameraRef.current.lookAt(0,0,0);//指向mesh对应的位置
   }
   // 创建几何体
   const setGeometry = () => {
      // example 1：平面UV贴图
      // getPlaneGeomery() 
      // example 2:将一个图片设置为3D效果
      setImgto3D()  
   }
   // 创建渲染器
   const setRenderer = () => {
      // 创建渲染器对象
      rendererRef.current = new THREE.WebGLRenderer();
      rendererRef.current.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)
      rendererRef.current.render(sceneRef.current, cameraRef.current); //执行渲染操作
      document.getElementById('webgl').appendChild(rendererRef.current.domElement);
      // 6. 轨道控制器
      const controls = new OrbitControls(cameraRef.current, rendererRef.current.domElement)

      function animate(){
        requestAnimationFrame(animate)
        controls.update() 
        rendererRef.current.render(sceneRef.current, cameraRef.current)
      }
      animate()
   }
   // 平面
   const getPlaneGeomery = () => {
     // 1.带贴图的平面
     let planeGeomery = new THREE.PlaneGeometry(2,2);
    //  创建纹理器
     let textureLoader = new THREE.TextureLoader(); 
    //  加载纹理
     let texture = textureLoader.load(require(".././assets/img2/logo.png"))
     let aoMap = textureLoader.load(require(".././assets/img/yay.jpg"))
     // 色彩空间设置为sRGB
     texture.colorSpace = THREE.SRGBColorSpace;

     let planeMaterial = new THREE.MeshBasicMaterial({
       map: texture,//加载纹理
       aoMap,
    })
    // planeMaterial.map = texture; //可以这样单独设置
    let plane = new THREE.Mesh(planeGeomery, planeMaterial);

    // 2.不贴图的平面
    const geometry = new THREE.BufferGeometry()
    const vertices = new Float32Array([-1.5,-1.0,0.0,  1.0, -1.0,0.0, 1.0, 1.0, 0.0, 
        -1.0,1.0,0.0
    ])
    // 创建顶点属性
    geometry.setAttribute('position',new THREE.BufferAttribute(vertices, 3));
    const indices = new Uint16Array([0,1,2,2,3,0]) 
    geometry.setIndex(new THREE.BufferAttribute(indices, 1))
    // 为几何体geometry设置法向向量，这样有环境贴图的时候才会自动反射光
    geometry.computeVertexNormals();
    geometry.translate(1.5,0,0)
    geometry.rotateX(Math.PI/4)
    geometry.scale(2,3,2)
    let planeMaterial2 = new THREE.MeshBasicMaterial({ 
        //  color: 0xffffff,
         map: texture,//加载纹理,但是没有uv属性
         side: THREE.DoubleSide,//双面都可看到
    })
    let plane2 = new THREE.Mesh(geometry, planeMaterial2);
    plane.position.set(3,0,0)
    plane2.position.set(-3,0,0)

    // 3. UV：将有贴图的平面映射到没有贴图的平面
    /**
     * 平面是4个角，对应UV的四组坐标，每2个一组，
     * 4个角默认是从左下角开始映射
     * 如果有两个点一样，那就是这两个点之间（采样）一模一样，可以改坐标试一下
     */
    const uv = new Float32Array([
        0,0,0,0,1,1,0,1
    ])
    // 将uv坐标设置到物体上，2代表是2个一组
    geometry.setAttribute("uv",new THREE.BufferAttribute(uv,2))

    sceneRef.current.add(plane);
    sceneRef.current.add(plane2);

    sceneRef.current.background = new THREE.Color(0x33cc33)

   }
   const setImgto3D = () => {
     // 1.带贴图的平面
     let planeGeomery = new THREE.PlaneGeometry(5,8,12);
    //  创建纹理器
     let textureLoader = new THREE.TextureLoader(); 
    //  加载纹理
     let texture = textureLoader.load(require(".././assets/img2/logo.png"))
    //  let material = new THREE.MeshBasicMaterial({ map: texture, side: THREE.DoubleSide, })


     // 将图片通过着色器绘制为3D效果，需要用到着色器材质ShaderMaterial
     const mouse = new THREE.Vector2();
     let depthTexture = textureLoader.load(require(".././assets/img/light.jpg"))
     let material = new THREE.ShaderMaterial({ 
       uniforms: {
         uTexture: { value: texture },
         uDepthTexture: { value: depthTexture }, 
         uMouse: {value: mouse}
       },
       vertexShader:`
        varying vec2 vUv;
        void main(){
          vUv = uv;
          gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
        }
       `,
       fragmentShader:`
       uniform sampler2D uTexture;
       uniform sampler2D uDepthTexture;
       uniform vec2 uMouse;
       uniform vec2 vUv;
       void main(){
         vec4 color = texture2D(uTexture, vUv);
         vec4 depth = texture2D(uDepthTexture, vUv);
         float depthValue = depth.r;
         float x = vUv.x + uMouse.x*0.01*depthValue;
         float y = vUv.y + uMouse.y*0.01*depthValue;
         vec4 newColor = texture2D(uTexture, vec2(x,y));
         gl_FragColor = newColor;
       }
       `
      })

     let plane = new THREE.Mesh(planeGeomery, material)
     sceneRef.current.add(plane)
   }

  return (
    <div>
      <h1>UV映射；图片设置3D效果</h1>
      <div id="webgl" style={{marginTop: 10,marginLeft: 10}}></div>
    </div>
  );
}
export default connect(({common})=>({
  userInfo: common.userInfo,
}))(UvPage)